------------------------------------------------- Understanding Zelda 1 Screens, Columns, and Tiles ------------------------------------------------- This document helps the reader understand how The Legend of Zelda stores it's screen data. Overworld Tile Data ------------------- The tile is the basic graphical unit on the NES. Each tile is 8x8 pixels. Tiles are further grouped into blocks, a.k.a. "meta-tiles", consisting of four tiles per block (think of the question mark block in Super Mario Bros). Each block is 16x16 pixels. There are three types of overworld blocks in Zelda. The first type is an arbitray set of 4 tiles represented by 4 bytes. There are 16 blocks of this type which are indexed as 0x00-0x0F. They are located at 0x1699C (headered). For example, block 0x05 located at 0x169D8 is the solid ocean/water block which consists of the 4 bytes 90 95 90 95 which are rendered to screen as: 90 90 95 95 The first four blocks are used to render the dungeon passage and dungeon item screens. One block is unused. 00: 24 24 24 24 Dungeon Passages Top of Stairs (black) 01: 6F 6F 6F 6F Dungeon Passages Stairs 02: F3 F3 F3 F3 Dungeon Passages Background (blocked) 03: FA FA FA FA Dungeon Passages Walls (bricks) 04: 98 95 26 26 Unused <-- 05: 90 95 90 95 Ocean 06: 8F 90 8F 90 Shore top edge 07: 95 96 95 96 Shore bottom edge 08: 8E 93 90 95 Shore left edge 09: 90 95 92 97 Shore right edge 0A: 74 74 75 75 Mountain Stairs 0B: 76 77 76 77 Bridge 0C: F3 24 F3 24 Dungeons Passages Walkable Space (black) / Cave Entrance in OW 0D: 24 24 24 24 Overworld Caves Ground 0E: 26 26 26 26 Overworld Ground 0F: 89 88 8B 88 Waterfall The second type of block is an ordered sequence of tiles represented by a single byte. These blocks are indexed as 0x10-0x37 and are located at 0x169D4. For example, block 0x12 is the stair block which consists of a single hex byte, 0x70, which is expanded and rendered to screen as 70 71 72 73, in the following orientation: 70 72 71 73 The third type of block is the special block which is a subset of the second type. They are indexed by 0x26-0x2B and reference tiles 0xE5-0xEA. The value of tile is ignored and is instead replaced by the table at 0x16986, rendering a sequence starting at that id. 26: C8 Pushable Rock (C8 C9 CA CB) 27: D8 Bombable Wall (D8 D9 DA DB) 28: C4 Burnable Tree (C4 C5 C6 C7) 29: BC Pushable Tomb (BC BD BE BF) 2A: C0 Pushable Armos (C0 C1 C2 C3) (unused) 2B: C0 Bombable Armos (C0 C1 C2 C3) (unused) Overworld Column Data --------------------- Zelda overworld screens are made up of 16 columns each. Each column is made up of 11 blocks, with each block made of 4 tiles. Each column in a screen is selected from one of 16 column groups, each of which has the capacity to hold 16 columns. Zelda ships with only 9 or 10 columns in each group. There's currently no graphical tool which is capable of modifying columns but Zelda Map Generator [1] can help you see what you're doing. Here's some crude ascii art to visualize a single column. :: <-- one block made up of 4 tiles :: :: :: :: :: :: :: :: :: :: <-- 11 blocks total This would be straightforward enough but Zelda also uses a rudimentary compression scheme to store the columns. This compression allows any given block to be repeated once and also allows for one column to start in the middle of another. Let's take a look at an example with no compression. 1B 1B 0E 0E 0E 0E 0E 0E 0E 1A 1B (11 hexadecimal bytes) This basic column contains two rock blocks at the top, followed by 7 ground blocks, and two more rock blocks at the bottom. If there was no compression applied it would be stored in the data as above. The compression scheme uses bitmasks to determine where a column starts and if any given block is repeated. A single block can be both the start of column and also be repeated. Each byte in the column consists of 8 bits made up of the following information: x... .... Start of Column (0x80 or 0b10000000) .x.. .... Repeat Block Once (0x40 or 0b01000000) ..xx xxxx Block ID (0x00-0x3F, 63 possible blocks total, only are 55 used) Let's look at how the same column is actually stored once compression is applied: DB 4E 4E 4E 0E 1A 1B Now let's break that down: DB = 0x1B + 0x80 (start of column) + 0x40 (repeat once) 4E = 0x0E + 0x40 (repeat once) 4E = 0x0E + 0x40 (repeat once) 4E = 0x0E + 0x40 (repeat once) 0E = 0x0E (no bitmask applied) 1A = 0x1A (no bitmask applied) 1B = 0x1B (no bitmask applied) Let's further complicate things with another example. A sequence of three uncompressed columns that looks like this: 1B 1B 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 1A 1B You can easily see the repetition. This is how those same three columns are actually stored when compressed: DB F7 F7 77 77 37 77 1A 1B These 9 bytes represent the same 33 bytes used by the three columns shown above! Two of the columns start within the first one, so all three share most of the blocks. Let's break it down: DB = 0x1B + 0x80 + 0x40 (start of column, repeat once) <-- First column starts here F7 = 0x37 + 0x80 + 0x40 (start of column, repeat once) <-- Second column starts here F7 = 0x37 + 0x80 + 0x40 (start of column, repeat once) <-- Third column starts here 77 = 0x37 + 0x40 (repeat once) 77 = 0x37 + 0x40 (repeat once) 37 = 0x37 (no bitmask applied) <-- First column ends here (11 bytes total) 77 = 0x37 + 0x40 (repeat once) <-- Second column ends here 1A = 0x1A (no bitmask applied) 1B = 0x1B (no bitmask applied) <-- Third column ends here That's how columns work. Now let's see where the column groups are located and how they're referenced. Overworld Columns Groups ------------------------ There's a pointer table at 0x19D1F (headered address) which contains 16 pointers, one for each of the column groups (two bytes per pointer): D8 9B 0D 9C 3E 9C 80 9C C4 9C F6 9C 32 9D 6D 9D A8 9D E6 9D 27 9E 6C 9E A9 9E DF 9E 21 9F 55 9F Each pointer points to the start of a single column group. These are headerless addresses so add 0x10 to locate the group in ROM. D8 9B -> 15BD8 ; group 0 0D 9C -> 15C0D ; group 1 3E 9C -> 15C3E ; group 2 80 9C -> 15C80 ; group 3 C4 9C -> 15CC4 ; group 4 F6 9C -> 15CF6 ; group 5 32 9D -> 15D32 ; group 6 6D 9D -> 15D6D ; group 7 A8 9D -> 15DA8 ; group 8 E6 9D -> 15DE6 ; group 9 27 9E -> 15E27 ; group A 6C 9E -> 15E6C ; group B A9 9E -> 15EA9 ; group C DF 9E -> 15EDF ; group D 21 9F -> 15F21 ; group E 55 9F -> 15F55 ; group F Column ids contain two pieces of information: the column group (table above), and the column index in that group. For example, C1 is the waterfall column which is the 2nd column found in group C (C0 is the first column in that group). The screen rendering code starts at the relevant group pointer and traverses the bytes looking for start of column bits. It starts rendering the relevant column once it locates the start of column for the column index that its looking for. Overworld Screen Data --------------------- First recall that there are 16 column groups and that each group can contain up to 16 columns. Each hexadecimal byte that refers to a column contains the column's group id and column's index in that group. The first digit in the hexadecimal byte is the column group number: 0x00-0xF0. The second digit is the column number in that group: 0x00-0x0F. Let's take a look at some screen data. The data for each screen starts at 0x15428 (headered). Each screen consists of 16 bytes, one byte for each column. There's no compression. Let's take the starting screen as an example. It's located at 0x15B48. 01 - References column group 0 (1st group), column index 1 (2nd column) A7 - References column group A (11th), column index 7 (8th) 84 - References column group 8 (9th), column index 4 (5th) 90 - References column group 9 (10th), column index 0 (1st) 10 - References column group 1 (2nd), column index 0 (1st) 02 - References column group 0 (1st), column index 2 (3rd) A5 - References column group A (11th), column index 5 (6th) 08 - References column group 8 (9th), column index 8 (9th) 08 - " A0 - References column group A (11th), column index 0 (1st) 06 - " 06 - " 06 - " 06 - " 01 - References column group 0 (1st), column index 1 (2nd) 01 - " Pretty straightforward. The game code first locates the group using the pointer and then starts traversing through bytes looking for the start-of-column bitmask. Once it locates the start-of-column for the requested column it then reads, uncompresses, and writes the column data to the nametable on the fly. It does that every time for every column on every screen. It's important to note that the screen definitions can be resued. There are a total of 128 overworld screens but only 121 screen definitions (excluding dungeon passages and caves). That means that 7 of the screens are shared in the overworld. The data table at 0x18590 (headered) contains the screen index in the lower 7 bits for each of the 128 overworld screens: .xxx xxxx Screen Index That covers the overworld. Now let's look at dungeons. Dungeon Tile Data ----------------- Dungeon floor layouts are constructed from only 8 possible blocks, indexed as 0x00-0x07 (not including walls and doors). The relevant 8 bytes are located at 0x16728 (headered) and are as follows: 00: B0 Block (B0 B1 B2 B3) 01: 74 Floor (74 75 76 77) 02: 94 Monster Right Facing (94 95 96 97 98) 03: B4 Monster Left Facing (B4 B5 B6 B7 B8) 04: 70 Stairs (70 71 72 73) 05: 68 Sand (68 68 68 68) 06: F4 Water (F4 F4 F4 F4) 07: 24 Black (24 24 24 24) The first 5 bytes (00-04) serve as the first tile in a continual sequence, while the last three (05-07) are repeated 4 times. Dungeon Column Data ------------------- Dungeon column definitions consist of 1-7 bytes which refer to the dungeon blocks above. The format is a bit different from the overworld columns. Each byte in the column consists of 8 bits made up of the following information: x... .... Start of a column definition .xxx .... Number of additional times the tile is repeated (0-6 times) .... x... Unused .... .xxx Block Index (0x00-0x07) Let's look at the first two columns in the first group to see how compression is applied: The first column consists of one single byte: 0xE1. In binary that's 0b11100001, or as grouped above: 1... .... Start of a column set .110 .... Repeat the tile 6 additional times (7 total) .... 0... Unused .... .001 Block 1 (Floor) The second column is 3 bytes: 80 C1 00 80 (0b10000000) = Start of column, no repeat, Block 0 (Block) C1 (0b11000001) = Start of column (another column starts right here), repeated 4 more times (5 total), Block 1 (Floor) 00 (0b00000000) = No repeat, Block 0 (Block) Dungeon Column Groups --------------------- The column group pointers are located at 0x16714 (headered). ; these are headerless addresses, add 0x10 to locate the group in rom D6 A2 -> 162D6 ; group 0 E6 A2 -> 162E6 ; group 1 04 A3 -> 16304 ; group 2 15 A3 -> 16315 ; group 3 26 A3 -> 16326 ; group 4 3D A3 -> 1633D ; group 5 54 A3 -> 16354 ; group 6 65 A3 -> 16365 ; group 7 77 A3 -> 16377 ; group 8 91 A3 -> 16391 ; group 9 Dungeon Screens Data -------------------- Dungeon screen definitions are located at 0x160EE (headered) and consist of 12 bytes apiece. Wall data is not included in the screen definition since it's always the same. Door information is also in another table. Other than that the format is the same as for the overworld. See: Overworld Screen Data above. The screen indices are stored in the lower 6 bits of each byte in the data tables at 0x18890 (levels 1-6) and 0x18B90 (levels 7-9): ..xx xxxx Screen Index Related Resources ----------------- Be sure to check out Zelda Map Generator [1] to help you out. The Zelda Expansion Hack [2] expands the number of useable tiles, blocks, columns, and screens. [1] https://www.romhacking.net/utilities/1556/ [2] https://www.romhacking.net/hacks/5950/ Happy hacking!